/**
 * WMGeo - A Geocaching PDA application
 * (c) Michal Kuchta 2008-2009
 */
 
#pragma once
 
#include "../stdafx.h"
#include "sqlite3.h"

// Forward...
class SQLStatement; 

/**
 * SQLite C++ wrapper
 */
class SQLite {
	// Public methods
	public:
		SQLite();
		~SQLite();
		
		// Error exception
		class Error {	
			// Public methods
			public:
				/**
				 * Constructor.
				 * @param db SQLite instance that triggered the error
				 */
				Error(SQLite *db): m_pDb(db) {
					this->m_iErrCode = ::sqlite3_errcode(this->m_pDb->m_pDatabase);
					this->m_pErrMessage = (wchar_t *)sqlite3_errmsg16(this->m_pDb->m_pDatabase);
				} // SQLite::Error::Error()
				
				/**
				 * Return error code of the error
				 * @return Error code
				 */
				inline int getErrorCode() {
					return this->m_iErrCode;
				} // SQLite::Error::getErrorCode()
				
				/**
				 * Return error message of this error
				 * @return Error message in heap-allocated buffer.
				 */
				inline const wchar_t *getErrorMessage() {
					return this->m_pErrMessage.GetBuffer();
				} // SQLite::Error::getErrorMessage()
		
			// Protected members
			protected:
				int m_iErrCode;
				CString m_pErrMessage;
				SQLite *m_pDb;
		};
		
		int Open(CString dbFile);
		int Close();
		SQLStatement Prepare(CString query);
		int Execute(CString query);
		int LastInsertId();
		const wchar_t *GetLastError();
		inline const CString &getFileName() { return this->m_sDbFile; }
		
	// Protected members
	protected:
		sqlite3 *m_pDatabase;		/**< SQLite database connection */
		char *m_pLastError;			/**< Last SQL error */
		CString m_sDbFile;			/**< Database file currently opened */
}; // class SQLite

/**
 * SQL result
 */
class SQLStatement {
	public:
		SQLStatement(SQLite *sqlite, sqlite3_stmt *statement);
		SQLStatement(SQLStatement const &sqlstatement);
		~SQLStatement();
		
		// Binding variables to statements
		void Bind(int index, const void *value, int length);
		void Bind(int index, double value);
		void Bind(int index, int value);
		void Bind(int index, sqlite3_int64 value);
		void Bind(int index);
		void Bind(int index, const char *value);
		
		// Executing the statement
		int Step();
		
		// Get column values
		const void *ColumnB(int index, int *length);
		int ColumnI(int index);
		double ColumnD(int index);
		sqlite3_int64 ColumnI64(int index);
		const unsigned char *ColumnT(int index);

	// Protected members	
	protected:
		SQLite *m_pSQLite;				/**< Working SQLite database */
		sqlite3_stmt *m_pStatement;		/**< Prepared statement */
		int *m_iInstanceCount;			/**< Number of instances of this statement */
}; // class SQLStatement